package com.hoolai.synroom.threadpool;

import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;

/**
 * <b>功能描述：</b><br>
 * <b>项目名称：</b>gamelogic3<br>
 * <b>修改记录：</b><br>
 * @author yizhuan
 * @date 2011-12-22下午01:42:05<br>
 * TODO
 */
public class SynRoomBusinessThreadPool {

    private static final Logger logger = Logger.getLogger("synfight");

    private final ThreadPoolExecutor executor;
    
    
    
    /**
     * The synRoom business thread factory
     */
    static class SynRoomBusinessThreadFactory implements ThreadFactory {
        final ThreadGroup group;
        final AtomicInteger threadNumber = new AtomicInteger(1);
        final String namePrefix;

        SynRoomBusinessThreadFactory(String namePrefix) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null)? s.getThreadGroup() :
                                 Thread.currentThread().getThreadGroup();
            this.namePrefix = namePrefix +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
    
    public SynRoomBusinessThreadPool(int minThreadNum, int maxThreadNum, int queueSize, String namePrefix) {
        executor = new ThreadPoolExecutor(minThreadNum, maxThreadNum, 30000L, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueueWrap(queueSize), new SynRoomBusinessThreadFactory(namePrefix), new RejectedExecutionHandler() {
                    
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        logger.error("------------------------------------------------");
                        logger.error("executor a businessTask, but the queue is full!!");
                        logger.error("------------------------------------------------");
                        SynRoomTask synRoomTask = (SynRoomTask) r;
                        if(synRoomTask.isImportantTask) {
                            executor.execute(r);
                        }
                    }
                });
    }
    
    public SynRoomBusinessThreadPool(int minThreadNum, int maxThreadNum, int queueSize) {
        this(minThreadNum, maxThreadNum, queueSize, "SynRoomBusinessThreadPool");
    }
    
    public int getThreadNum() {
        return executor.getPoolSize();
    }
    
    public int getQueueNum() {
        return executor.getQueue().size();
    }
    
    public long getCompleteTaskNum() {
        return executor.getCompletedTaskCount();
    }
    
    public long getScheduleTaskNum() {
        return executor.getTaskCount();
    }
    
    public int getActiveThreadNum() {
        return executor.getActiveCount();
    }
    
    public int getMaxThreadNumInHistory() {
        return executor.getLargestPoolSize();
    }

    public void execute(SynRoomTask command) {
        executor.execute(command);
    }
    
    /**
     * An annoying wrapper class to convince javac to use a
     * ArrayBlockingQueue<SynRoomTask> as a BlockingQueue<Runnable>
     */
    private static class ArrayBlockingQueueWrap extends AbstractQueue<Runnable> implements BlockingQueue<Runnable>, java.io.Serializable {

        private static final long serialVersionUID = 7112515911288121357L;
        private final ArrayBlockingQueue<SynRoomTask> q;
        
        public ArrayBlockingQueueWrap(int capacity) {
            q = new ArrayBlockingQueue<SynRoomTask>(capacity); 
        }
        
        public Runnable poll() { return q.poll(); }
        public Runnable peek() { return q.peek(); }
        public Runnable take() throws InterruptedException { return q.take(); }
        public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
            return q.poll(timeout, unit);
        }

        public boolean add(Runnable x) {
            return q.add((SynRoomTask) x);
        }
        public boolean offer(Runnable x) {
            return q.offer((SynRoomTask) x);
        }
        public void put(Runnable x) throws InterruptedException {
            q.put((SynRoomTask) x);
        }
        public boolean offer(Runnable x, long timeout, TimeUnit unit) throws InterruptedException {
            return q.offer((SynRoomTask) x, timeout, unit);
        }

        public Runnable remove() { return q.remove(); }
        public Runnable element() { return q.element(); }
        public void clear() { q.clear(); }
        public int drainTo(Collection<? super Runnable> c) { return q.drainTo(c); }
        public int drainTo(Collection<? super Runnable> c, int maxElements) {
            return q.drainTo(c, maxElements);
        }

        public int remainingCapacity() { return q.remainingCapacity(); }
        public boolean remove(Object x) { return q.remove(x); }
        public boolean contains(Object x) { return q.contains(x); }
        public int size() { return q.size(); }
        public boolean isEmpty() { return q.isEmpty(); }
        public Object[] toArray() { return q.toArray(); }
        public <T> T[] toArray(T[] array) { return q.toArray(array); }
        public Iterator<Runnable> iterator() {
            return new Iterator<Runnable>() {
                private Iterator<SynRoomTask> it = q.iterator();
                public boolean hasNext() { return it.hasNext(); }
                public Runnable next() { return it.next(); }
                public void remove() { it.remove(); }
            };
        }
    }

}
